package com.weilan.ark3.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.weilan.ark3.buffer.DataArray;
import com.weilan.ark3.buffer.DataArray2;
import com.weilan.ark3.buffer.MsgQueue;
import com.weilan.ark3.buffer.OverallSituation;
import com.weilan.ark3.common.GlobalParam;
import com.weilan.ark3.entity.*;
import com.weilan.ark3.mapper.ControlRtuMapper;
import com.weilan.ark3.mapper.ModbusConfMapper;
import com.weilan.ark3.sqlite.*;
import com.weilan.ark3.tcp.TcpSlave;
import com.weilan.ark3.service.ModbusConfService;

import com.weilan.ark3.utils.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

import static com.weilan.ark3.buffer.DataArray.*;
import static com.weilan.ark3.buffer.OverallSituation.*;


/**
 *
 */
@Service
public class ModbusConfServiceImpl extends ServiceImpl<ModbusConfMapper, ModbusConf> implements ModbusConfService {
    @Autowired
    private ControlRtuMapper controlRtuMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private SQLiteUtils sqLiteUtils;
//    @Autowired
//    private SerialPortSlave serialPortSlave;

    Logger tcpServer = LoggerFactory.getLogger("TCPServer_Appender");

    @Override
    public synchronized void writeModBusData2DB() {
        //tcpServer.info("数据存储定时任务开始时间");
        long start = System.currentTimeMillis();
        //创建ControlRtu类型的对象并将每个对象的IsRead属性为1
        LambdaQueryWrapper<ControlRtu> wrapper = new LambdaQueryWrapper<>();
        //根据创建的对象的条件去数据库查询tb_control_rtu表并获取该类型的对象存放在集合
        List<ControlRtu> rtuList = controlRtuMapper.selectList(wrapper);
        // 获取当前系统时间
        LocalDateTime now = LocalDateTime.now();
        // 定义日期时间格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        // 格式化当前时间
        String formattedDateTime = now.format(formatter);

        //遍历对象集合
        rtuList.forEach(e -> {
            //获取对象模块名
            String moduleName = e.getModuleName();
            //数据长度
            int len = e.getLen();
            //是否存储
            int isMemory = e.getIsMemory();
            if (isMemory == 1) {
                //字段起始地址
                String startHex = HexUtils.decToHex(e.getStart());
                //字段结束地址
                String endHex = HexUtils.decToHex(e.getEnd());
                String key = e.getSlaveId() + ":" + e.getModuleName() + ":" + e.getDeviceId() + ":" + e.getInstructName();
                String datacache = OverallSituation.CacheData.get(key);
                String data = StringUtils.removeString(datacache);
                //根据起始地址，长度，模块名查询tb_modbus_conf表，只返回name值存储到集合中。
                List<String> moduleNameList = controlRtuMapper.selectModuleName(startHex, endHex, moduleName);
                if (moduleNameList.size() == len && data != null) {
                    moduleNameList.add(0, "deviceId");
                    moduleNameList.add(0, "slaveId");
                    moduleNameList.add(0, "date");
                    //按照（毫秒，设备id，reidsValues）生成字符串
                    String saveValues = "'" + formattedDateTime + "'," + e.getSlaveId() + "," + e.getDeviceId() + "," + data;
                    //获取指令名称字符串
                    String instructName = e.getInstructName();
                    //获取当前时间转化成字符串
                    String dateStr = DateUtils.currentTimeNamingDatabase();
                    //拼接字符串
                    String newTableName = instructName + "_" + dateStr;
                    //存入数据库
                    sqLiteUtils.insertToDB(newTableName, moduleNameList, saveValues);
                }
            }
        });
        long end = System.currentTimeMillis();
        //tcpServer.info("数据存储定时任务执行方法总耗时{}ms", (end - start));
    }

    /**
     * 存储故障信息
     */
    @Override
//    public void writeModBusFaultData2DB() {

    public void writeModBusFaultData2DB() {
        //tcpServer.info("故障信息定时任务开始时间");
        long start = System.currentTimeMillis();
        DataArray.slaveDataMap.forEach((k, v) -> {
            short[] rowData = new short[]{v[120], v[121], v[122], v[123], v[517], v[518],
                    v[1027], v[1028], v[1029], v[1030], v[1035], v[1036], v[1037], v[1038],
                    v[2043], v[2044], v[2045], v[3043], v[3044], v[3045], v[4030], v[4032], v[4033]};
            String[] dataToRedis = new String[rowData.length];
            String[] dataCMD = dataToCacheCMD.get(k);
            //故障信息
            StringBuilder faultInfo = new StringBuilder();
            // 获取当前系统时间
            LocalDateTime now = LocalDateTime.now();
            // 定义日期时间格式
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            // 格式化当前时间
            String formattedDateTime = now.format(formatter);
            //将获取的故障位转换为16位存入dataToRedis数组中
            for (int i = 0; i < rowData.length; i++) {
                dataToRedis[i] = StringUtils.convertTo16BitBinary(rowData[i]);
            }
            //存入全局redis中
            for (int i = 0; i < GlobalParam.cacheFaultKey.length; i++) {
                if (!"0000000000000000".equals(dataToRedis[i]) && !dataToRedis[i].equals(dataCMD[i])) {
                    OverallSituation.CacheData.put(GlobalParam.cacheFaultKey[i], String.valueOf(dataToRedis[i]));
                    String str = StringUtils.getFaultInfo(dataToRedis[i], GlobalParam.cacheFaultKey[i], k);
                    if (!("".equals(str))) {
                        faultInfo.append(str);
                    }
                }
                dataCMD[i] = dataToRedis[i];

            }
            // 删除末尾的逗号
            if (faultInfo.length() > 0) {
                faultInfo.deleteCharAt(faultInfo.length() - 1);
            }
            if (faultInfo.length() != 0) {
                // 使用逗号分隔字符串
                String faultInfoStr = faultInfo.toString();
                String[] parts = faultInfoStr.split(",");
                // 遍历字符串数组并打印每个部分
                for (String part : parts) {
                    SQLiteUtilsFault.insertToDB2("fault_info", formattedDateTime, part, k);
                }
            }
        });
        long end = System.currentTimeMillis();
        //tcpServer.info("故障信息定时任务执行方法总耗时{}ms", (end - start));
    }

    @Override
    /**
     * 将PHC地址数据存储EMS地址
     */
    public void writerToEMS() {
        //tcpServer.info("赋值定时任务开始时间");
        long start = System.currentTimeMillis();
        if (slaveDataMap.get(1) == null) {
            return;
        }
        short[] EMSData = DataArray.slaveDataMap.get(1);
        ParamDto param = SQLiteParamUtils.query();
        //获取SOC相关参数
        SocDto socDto = SocUtils.query();
        ConfigDto configDto = SQLiteConfigUtils.query();
        int soc_h = Integer.parseInt(param.getSoc_h());
        int soc_l = Integer.parseInt(param.getSoc_l());
        int back_power = Integer.parseInt(param.getBack_power());
        int allowance = param.getGrid_alw();
        int stepSize = param.getStep_size();
        int pMax = Integer.parseInt(param.getP_max());
        int antiReflux = param.getAnti_reflux();
        int patternFlag = param.getPattern_flag();
        int expansionMark = param.getExpansion_mark();
        int pv_max = param.getPv_max();
        int bcmSocl = param.getBcm_socl();

        //soc参数值
        int min_soc = socDto.getMin_soc();
        int bcp_soc = socDto.getBcp_soc();
        int dcm_soc = socDto.getDcm_soc();
        int max_soc = socDto.getMax_soc();
        short EMSstate = 3;
        short EMSmode = 1;
        short allowChargeLimits = 0;
        short allowDisChargeLimits = 0;
        short Sys_Power = 0;
        short load_Power = 0;
        short Mppt_Power = 0;
        int Intput_High = 0;
        int Intput_Low = 0;
        int Output_High = 0;
        int Output_Low = 0;
        short Sys_SOC = 0;
        short RW_SysState = 2;
        short RW_Sys_Power = 0;
        short RW_Sys_Controller = 1;
        short SOCH_Nocharge = 0;
        short SOCL_Nodischarge = 0;
        for (int i = tcpSlaveStartId; i < arkDeviceNumber + tcpSlaveStartId; i++) {
            if (slaveDataMap.get(i) == null) {
                return;
            }
            short[] shorts1 = slaveDataMap.get(i);
            short UCState = shorts1[100];
            short UCMode = shorts1[101];
            short allowCharge = shorts1[104];//允许充电
            short allowDisCharge = shorts1[105];//允许放电
            short sysPower = shorts1[107];//允许放电
            short loadPower = shorts1[109];//负载
            short MpptPower = shorts1[110];//mppt功率
            int IntputHigh = shorts1[111];//输入有功高位
            int IntputLow = shorts1[112];//输入有功低位
            int OutputHigh = shorts1[113];//输出有功高位
            int OutputLow = shorts1[114];//输出有功低位
            short SOC = shorts1[248];//soc
            short RWSysState = shorts1[301];//
            short RWSysPower = shorts1[302];//
            short RWSysController = shorts1[331];//
            short SOCHNocharge = shorts1[4017];//高压禁充
            short SOCLNodischarge = shorts1[4018];//低压禁放
            EMSstate = CollectUtils.getState(EMSstate, UCState);
            EMSmode = CollectUtils.getMode(EMSmode, UCMode);
            allowChargeLimits = CollectUtils.getAdd(allowChargeLimits, allowCharge);
            allowDisChargeLimits = CollectUtils.getAdd(allowDisChargeLimits, allowDisCharge);
            Sys_Power = CollectUtils.getAdd(Sys_Power, sysPower);
            load_Power = CollectUtils.getAdd(load_Power, loadPower);
            Mppt_Power = CollectUtils.getAdd(Mppt_Power, MpptPower);
            Intput_High = CollectUtils.getAddElectricEnergy(Intput_High, IntputHigh);
            Intput_Low = CollectUtils.getAddElectricEnergy(Intput_Low, IntputLow);
            Output_High = CollectUtils.getAddElectricEnergy(Output_High, OutputHigh);
            Output_Low = CollectUtils.getAddElectricEnergy(Output_Low, OutputLow);
            Sys_SOC = CollectUtils.getAdd(Sys_SOC, SOC);
            RW_SysState = CollectUtils.getRWState(RW_SysState, RWSysState);
            RW_Sys_Power = CollectUtils.getAdd(RW_Sys_Power, RWSysPower);
            RW_Sys_Controller = CollectUtils.getController(RW_Sys_Controller, RWSysController);
            SOCH_Nocharge = CollectUtils.getSOCState(SOCHNocharge, SOCH_Nocharge);
            SOCL_Nodischarge = CollectUtils.getSOCState(SOCLNodischarge, SOCL_Nodischarge);
        }
//        System.out.println("1:"+Intput_High+",2:"+Intput_Low+",3:"+Output_High+",4:"+Output_Low);
        EMSData[1] = EMSstate;//工作状态
        EMSData[2] = EMSData[60];//工作模式
        EMSData[3] = EMSData[62];//控制模式
        EMSData[4] = allowChargeLimits;//允许充电
        EMSData[5] = allowDisChargeLimits;//允许放电
        EMSData[6] = Sys_Power;//有功功率
        if (com2State == 1) {
            //电表功率数据
            short L1_High1 = DataArray2.data[12];
            short L1_low1 = DataArray2.data[13];
            short L2_High1 = DataArray2.data[14];
            short L2_low1 = DataArray2.data[15];
            short L3_High1 = DataArray2.data[16];
            short L3_low1 = DataArray2.data[17];
            short Grid_meter_power = (short) HexUtils.Power(L1_High1, L1_low1, L2_High1, L2_low1, L3_High1, L3_low1);
            EMSData[8] = Grid_meter_power;
            int pv_power = EMSData[14003];
            int load = Grid_meter_power + Sys_Power + pv_power;
            EMSData[7] = (short) -Math.abs(load);
        } else {
            EMSData[7] = load_Power;//负载有功功率
            EMSData[8] = (short) -Sys_Power;//电网有功功率
        }
        EMSData[9] = Mppt_Power;//Mppt总功率
        EMSData[10] = (short) (Intput_High + (Intput_Low / 65535));//输入有功高
        EMSData[11] = (short) (Intput_Low % 65535);//
        EMSData[12] = (short) (Output_High + (Output_Low / 65535));//
        EMSData[13] = (short) (Output_Low % 65535);//
        EMSData[16] = SOCH_Nocharge;
        EMSData[17] = SOCL_Nodischarge;
        EMSData[26] = (short) (Sys_SOC / arkDeviceNumber);
        EMSData[27] = ComFault.FaultNum();// 系统告警0
        EMSData[28] = ComFault.Sys_Alarm_1(); // 系统告警1
        EMSData[29] = ComFault.Sys_Fault_0(); // 系统故障0

        LocalDateTime now = LocalDateTime.now();
        EMSData[40] = (short) now.getYear(); // 年
        EMSData[41] = (short) now.getMonthValue(); // 月
        EMSData[42] = (short) now.getDayOfMonth(); // 日
        EMSData[43] = (short) now.getHour(); // 时
        EMSData[44] = (short) now.getMinute(); // 分
        EMSData[45] = (short) now.getSecond(); // 秒
        EMSData[46] = 768; // EMS版本号

        EMSData[51] = EMSData[73];
        EMSData[52] = EMSData[74];
        //PV功率
        EMSData[53] = EMSData[14003];


        EMSData[60] = (short) patternFlag;
        if (patternFlag == 4) {
            GlobalParam.fgState = 1;
            GlobalParam.backState = 0;
            GlobalParam.PVState = 0;
        } else if (patternFlag == 1 || patternFlag == 3 || patternFlag == 2) {
            GlobalParam.backState = 0;
            GlobalParam.fgState = 0;
            GlobalParam.PVState = 0;
            GlobalParam.socState = 0;
        } else if (patternFlag == 7 || patternFlag == 8 || patternFlag == 9 || patternFlag == 10 || patternFlag == 12) {
            GlobalParam.PVState = 1;
            GlobalParam.backState = 0;
            GlobalParam.fgState = 0;
            GlobalParam.socState = 1;
        }
        EMSData[61] = RW_SysState;
        if (ACU == 1) {
            short[] acudata = slaveDataMap.get(50);
            EMSData[62] = acudata[331];
        } else {
            EMSData[62] = RW_Sys_Controller;
        }
        if (ACU == 1) {
            short[] acudata = slaveDataMap.get(50);
            EMSData[63] = acudata[107];
        } else {
            EMSData[63] = RW_Sys_Power;
        }
//        System.out.println(EMSData[601]);
        EMSData[63] = RW_Sys_Power;
        EMSData[65] = (short) soc_h;
        EMSData[66] = (short) soc_l;
        EMSData[67] = (short) back_power;
        EMSData[68] = (short) allowance;
        EMSData[70] = (short) stepSize;
        EMSData[71] = (short) antiReflux;
        EMSData[76] = (short) pMax;
        EMSData[77] = (short) pv_max;
        EMSData[78] = (short) expansionMark;
        EMSData[79] = (short) bcmSocl;
        EMSData[80] = EMSData[14003];

        EMSData[81] = (short) min_soc;
        EMSData[82] = (short) bcp_soc;
        EMSData[83] = (short) dcm_soc;
        EMSData[84] = (short) max_soc;

        TcpSlave.slaveMap.get(1).setHoldingRegister(0, EMSData);
        long end = System.currentTimeMillis();
        //tcpServer.info("赋值定时任务执行方法总耗时{}ms", (end - start));
    }
}